Skip to content

Package: UUDecoderStream

UUDecoderStream

nameinstructionbranchcomplexitylinemethod
UUDecoderStream(InputStream)
M: 26 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
available()
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
decode()
M: 223 C: 0
0%
M: 24 C: 0
0%
M: 13 C: 0
0%
M: 37 C: 0
0%
M: 1 C: 0
0%
getMode()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getName()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
markSupported()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
read()
M: 28 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
read(byte[], int, int)
M: 27 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
readPrefix()
M: 48 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 13 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Distribution License v. 1.0, which is available at
6: * http://www.eclipse.org/org/documents/edl-v10.php.
7: *
8: * SPDX-License-Identifier: BSD-3-Clause
9: */
10:
11: /*
12: * @(#)UUDecoderStream.java 1.8 02/07/08
13: */
14:
15:
16:
17: package com.sun.xml.messaging.saaj.packaging.mime.util;
18:
19: import java.io.*;
20:
21: /**
22: * This class implements a UUDecoder. It is implemented as
23: * a FilterInputStream, so one can just wrap this class around
24: * any input stream and read bytes from this filter. The decoding
25: * is done as the bytes are read out.
26: *
27: * @author John Mani
28: * @author Bill Shannon
29: */
30:
31: public class UUDecoderStream extends FilterInputStream {
32: private String name;
33: private int mode;
34:
35: private byte[] buffer;         // cache of decoded bytes
36: private int bufsize = 0;        // size of the cache
37: private int index = 0;        // index into the cache
38: private boolean gotPrefix = false;
39: private boolean gotEnd = false;
40: private LineInputStream lin;
41:
42: /**
43: * Create a UUdecoder that decodes the specified input stream
44: * @param in the input stream
45: */
46: public UUDecoderStream(InputStream in) {
47:         super(in);
48:         lin = new LineInputStream(in);
49:         buffer = new byte[45]; // max decoded chars in a line = 45
50: }
51:
52: /**
53: * Read the next decoded byte from this input stream. The byte
54: * is returned as an <code>int</code> in the range <code>0</code>
55: * to <code>255</code>. If no byte is available because the end of
56: * the stream has been reached, the value <code>-1</code> is returned.
57: * This method blocks until input data is available, the end of the
58: * stream is detected, or an exception is thrown.
59: *
60: * @return next byte of data, or <code>-1</code> if the end of
61: * stream is reached.
62: * @exception IOException if an I/O error occurs.
63: * @see java.io.FilterInputStream#in
64: */
65:
66: @Override
67: public int read() throws IOException {
68:•        if (index >= bufsize) {
69:          readPrefix();
70:•         if (!decode())
71:                 return -1;
72:          index = 0; // reset index into buffer
73:         }
74:         return buffer[index++] & 0xff; // return lower byte
75: }
76:
77: @Override
78: public int read(byte[] buf, int off, int len) throws IOException {
79:         int i, c;
80:•        for (i = 0; i < len; i++) {
81:•         if ((c = read()) == -1) {
82:•                if (i == 0) // At end of stream, so we should
83:                  i = -1; // return -1, NOT 0.
84:                 break;
85:          }
86:          buf[off+i] = (byte)c;
87:         }
88:         return i;
89: }
90:
91: @Override
92: public boolean markSupported() {
93:         return false;
94: }
95:
96: @Override
97: public int available() throws IOException {
98:          // This is only an estimate, since in.available()
99:          // might include CRLFs too ..
100:          return ((in.available() * 3)/4 + (bufsize-index));
101: }
102:
103: /**
104: * Get the "name" field from the prefix. This is meant to
105: * be the pathname of the decoded file
106: *
107: * @return name of decoded file
108: * @exception IOException if an I/O error occurs.
109: */
110: public String getName() throws IOException {
111:         readPrefix();
112:         return name;
113: }
114:
115: /**
116: * Get the "mode" field from the prefix. This is the permission
117: * mode of the source file.
118: *
119: * @return permission mode of source file
120: * @exception IOException if an I/O error occurs.
121: */
122: public int getMode() throws IOException {
123:         readPrefix();
124:         return mode;
125: }
126:
127: /**
128: * UUencoded streams start off with the line:
129: * "begin <mode> <filename>"
130: * Search for this prefix and gobble it up.
131: */
132: private void readPrefix() throws IOException {
133:•        if (gotPrefix) // got the prefix
134:          return;
135:
136:         String s;
137:         for (;;) {
138:          // read till we get the prefix: "begin MODE FILENAME"
139:          s = lin.readLine(); // NOTE: readLine consumes CRLF pairs too
140:•         if (s == null)
141:                 throw new IOException("UUDecoder error: No Begin");
142:•         if (s.regionMatches(true, 0, "begin", 0, 5)) {
143:                 try {
144:                  mode = Integer.parseInt(s.substring(6,9));
145:                 } catch (NumberFormatException ex) {
146:                  throw new IOException("UUDecoder error: " + ex.toString());
147:                 }
148:                 name = s.substring(10);
149:                 gotPrefix = true;
150:                 return;
151:          }
152:         }
153: }
154:
155: private boolean decode() throws IOException {
156:
157:•        if (gotEnd)
158:          return false;
159:         bufsize = 0;
160:         String line;
161:         do {
162:          line = lin.readLine();
163:
164:          /*
165:          * Improperly encoded data sometimes omits the zero length
166:          * line that starts with a space character, we detect the
167:          * following "end" line here.
168:          */
169:•         if (line == null)
170:                 throw new IOException("Missing End");
171:•         if (line.regionMatches(true, 0, "end", 0, 3)) {
172:                 gotEnd = true;
173:                 return false;
174:          }
175:•        } while (line.length() == 0);
176:         int count = line.charAt(0);
177:•        if (count < ' ')
178:          throw new IOException("Buffer format error");
179:
180:         /*
181:          * The first character in a line is the number of original (not
182:          * the encoded atoms) characters in the line. Note that all the
183:          * code below has to handle the <SPACE> character that indicates
184:          * end of encoded stream.
185:          */
186:         count = (count - ' ') & 0x3f;
187:
188:•        if (count == 0) {
189:          line = lin.readLine();
190:•         if (line == null || !line.regionMatches(true, 0, "end", 0, 3))
191:                 throw new IOException("Missing End");
192:          gotEnd = true;
193:          return false;
194:         }
195:
196:         int need = ((count * 8)+5)/6;
197: //System.out.println("count " + count + ", need " + need + ", len " + line.length());
198:•        if (line.length() < need + 1)
199:          throw new IOException("Short buffer error");
200:         
201:         int i = 1;
202:         byte a, b;
203:         /*
204:          * A correct uuencoder always encodes 3 characters at a time, even
205:          * if there aren't 3 characters left. But since some people out
206:          * there have broken uuencoders we handle the case where they
207:          * don't include these "unnecessary" characters.
208:          */
209:•        while (bufsize < count) {
210:          // continue decoding until we get 'count' decoded chars
211:          a = (byte)((line.charAt(i++) - ' ') & 0x3f);
212:          b = (byte)((line.charAt(i++) - ' ') & 0x3f);
213:          buffer[bufsize++] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));
214:
215:•         if (bufsize < count) {
216:                 a = b;
217:                 b = (byte)((line.charAt(i++) - ' ') & 0x3f);
218:                 buffer[bufsize++] =
219:                                 (byte)(((a << 4) & 0xf0) | ((b >>> 2) & 0xf));
220:          }
221:
222:•         if (bufsize < count) {
223:                 a = b;
224:                 b = (byte)((line.charAt(i++) - ' ') & 0x3f);
225:                 buffer[bufsize++] = (byte)(((a << 6) & 0xc0) | (b & 0x3f));
226:          }
227:         }
228:         return true;
229: }
230:
231: /*** begin TEST program *****
232: public static void main(String argv[]) throws Exception {
233:         FileInputStream infile = new FileInputStream(argv[0]);
234:         UUDecoderStream decoder = new UUDecoderStream(infile);
235:         int c;
236:
237:         try {
238:          while ((c = decoder.read()) != -1)
239:                 System.out.write(c);
240:          System.out.flush();
241:         } catch (Exception e) {
242:          e.printStackTrace();
243:         }
244: }
245: **** end TEST program ****/
246: }