src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/UUDecoderStream.java

Wed, 12 Jun 2013 14:47:09 +0100

author
mkos
date
Wed, 12 Jun 2013 14:47:09 +0100
changeset 384
8f2986ff0235
parent 0
373ffda63c9a
permissions
-rw-r--r--

8013021: Rebase 8005432 & 8003542 against the latest jdk8/jaxws
8003542: Improve processing of MTOM attachments
8005432: Update access to JAX-WS
Reviewed-by: mullan

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 /* FROM mail.jar */
aoqi@0 27 package com.sun.xml.internal.org.jvnet.mimepull;
aoqi@0 28
aoqi@0 29 import java.io.*;
aoqi@0 30
aoqi@0 31 /**
aoqi@0 32 * This class implements a UUDecoder. It is implemented as
aoqi@0 33 * a FilterInputStream, so one can just wrap this class around
aoqi@0 34 * any input stream and read bytes from this filter. The decoding
aoqi@0 35 * is done as the bytes are read out.
aoqi@0 36 *
aoqi@0 37 * @author John Mani
aoqi@0 38 * @author Bill Shannon
aoqi@0 39 */
aoqi@0 40
aoqi@0 41 final class UUDecoderStream extends FilterInputStream {
aoqi@0 42 private String name;
aoqi@0 43 private int mode;
aoqi@0 44
aoqi@0 45 private byte[] buffer = new byte[45]; // max decoded chars in a line = 45
aoqi@0 46 private int bufsize = 0; // size of the cache
aoqi@0 47 private int index = 0; // index into the cache
aoqi@0 48 private boolean gotPrefix = false;
aoqi@0 49 private boolean gotEnd = false;
aoqi@0 50 private LineInputStream lin;
aoqi@0 51 private boolean ignoreErrors;
aoqi@0 52 private boolean ignoreMissingBeginEnd;
aoqi@0 53 private String readAhead;
aoqi@0 54
aoqi@0 55 /**
aoqi@0 56 * Create a UUdecoder that decodes the specified input stream.
aoqi@0 57 * The System property <code>mail.mime.uudecode.ignoreerrors</code>
aoqi@0 58 * controls whether errors in the encoded data cause an exception
aoqi@0 59 * or are ignored. The default is false (errors cause exception).
aoqi@0 60 * The System property <code>mail.mime.uudecode.ignoremissingbeginend</code>
aoqi@0 61 * controls whether a missing begin or end line cause an exception
aoqi@0 62 * or are ignored. The default is false (errors cause exception).
aoqi@0 63 * @param in the input stream
aoqi@0 64 */
aoqi@0 65 public UUDecoderStream(InputStream in) {
aoqi@0 66 super(in);
aoqi@0 67 lin = new LineInputStream(in);
aoqi@0 68 // default to false
aoqi@0 69 ignoreErrors = PropUtil.getBooleanSystemProperty(
aoqi@0 70 "mail.mime.uudecode.ignoreerrors", false);
aoqi@0 71 // default to false
aoqi@0 72 ignoreMissingBeginEnd = PropUtil.getBooleanSystemProperty(
aoqi@0 73 "mail.mime.uudecode.ignoremissingbeginend", false);
aoqi@0 74 }
aoqi@0 75
aoqi@0 76 /**
aoqi@0 77 * Create a UUdecoder that decodes the specified input stream.
aoqi@0 78 * @param in the input stream
aoqi@0 79 * @param ignoreErrors ignore errors?
aoqi@0 80 * @param ignoreMissingBeginEnd ignore missing begin or end?
aoqi@0 81 */
aoqi@0 82 public UUDecoderStream(InputStream in, boolean ignoreErrors,
aoqi@0 83 boolean ignoreMissingBeginEnd) {
aoqi@0 84 super(in);
aoqi@0 85 lin = new LineInputStream(in);
aoqi@0 86 this.ignoreErrors = ignoreErrors;
aoqi@0 87 this.ignoreMissingBeginEnd = ignoreMissingBeginEnd;
aoqi@0 88 }
aoqi@0 89
aoqi@0 90 /**
aoqi@0 91 * Read the next decoded byte from this input stream. The byte
aoqi@0 92 * is returned as an <code>int</code> in the range <code>0</code>
aoqi@0 93 * to <code>255</code>. If no byte is available because the end of
aoqi@0 94 * the stream has been reached, the value <code>-1</code> is returned.
aoqi@0 95 * This method blocks until input data is available, the end of the
aoqi@0 96 * stream is detected, or an exception is thrown.
aoqi@0 97 *
aoqi@0 98 * @return next byte of data, or <code>-1</code> if the end of
aoqi@0 99 * stream is reached.
aoqi@0 100 * @exception IOException if an I/O error occurs.
aoqi@0 101 * @see java.io.FilterInputStream#in
aoqi@0 102 */
aoqi@0 103 @Override
aoqi@0 104 public int read() throws IOException {
aoqi@0 105 if (index >= bufsize) {
aoqi@0 106 readPrefix();
aoqi@0 107 if (!decode()) {
aoqi@0 108 return -1;
aoqi@0 109 }
aoqi@0 110 index = 0; // reset index into buffer
aoqi@0 111 }
aoqi@0 112 return buffer[index++] & 0xff; // return lower byte
aoqi@0 113 }
aoqi@0 114
aoqi@0 115 @Override
aoqi@0 116 public int read(byte[] buf, int off, int len) throws IOException {
aoqi@0 117 int i, c;
aoqi@0 118 for (i = 0; i < len; i++) {
aoqi@0 119 if ((c = read()) == -1) {
aoqi@0 120 if (i == 0) {// At end of stream, so we should
aoqi@0 121 i = -1; // return -1, NOT 0.
aoqi@0 122 }
aoqi@0 123 break;
aoqi@0 124 }
aoqi@0 125 buf[off+i] = (byte)c;
aoqi@0 126 }
aoqi@0 127 return i;
aoqi@0 128 }
aoqi@0 129
aoqi@0 130 @Override
aoqi@0 131 public boolean markSupported() {
aoqi@0 132 return false;
aoqi@0 133 }
aoqi@0 134
aoqi@0 135 @Override
aoqi@0 136 public int available() throws IOException {
aoqi@0 137 // This is only an estimate, since in.available()
aoqi@0 138 // might include CRLFs too ..
aoqi@0 139 return ((in.available() * 3)/4 + (bufsize-index));
aoqi@0 140 }
aoqi@0 141
aoqi@0 142 /**
aoqi@0 143 * Get the "name" field from the prefix. This is meant to
aoqi@0 144 * be the pathname of the decoded file
aoqi@0 145 *
aoqi@0 146 * @return name of decoded file
aoqi@0 147 * @exception IOException if an I/O error occurs.
aoqi@0 148 */
aoqi@0 149 public String getName() throws IOException {
aoqi@0 150 readPrefix();
aoqi@0 151 return name;
aoqi@0 152 }
aoqi@0 153
aoqi@0 154 /**
aoqi@0 155 * Get the "mode" field from the prefix. This is the permission
aoqi@0 156 * mode of the source file.
aoqi@0 157 *
aoqi@0 158 * @return permission mode of source file
aoqi@0 159 * @exception IOException if an I/O error occurs.
aoqi@0 160 */
aoqi@0 161 public int getMode() throws IOException {
aoqi@0 162 readPrefix();
aoqi@0 163 return mode;
aoqi@0 164 }
aoqi@0 165
aoqi@0 166 /**
aoqi@0 167 * UUencoded streams start off with the line:
aoqi@0 168 * "begin <mode> <filename>"
aoqi@0 169 * Search for this prefix and gobble it up.
aoqi@0 170 */
aoqi@0 171 private void readPrefix() throws IOException {
aoqi@0 172 if (gotPrefix) {
aoqi@0 173 return;
aoqi@0 174 }
aoqi@0 175
aoqi@0 176 mode = 0666; // defaults, overridden below
aoqi@0 177 name = "encoder.buf"; // same default used by encoder
aoqi@0 178 String line;
aoqi@0 179 for (;;) {
aoqi@0 180 // read till we get the prefix: "begin MODE FILENAME"
aoqi@0 181 line = lin.readLine(); // NOTE: readLine consumes CRLF pairs too
aoqi@0 182 if (line == null) {
aoqi@0 183 if (!ignoreMissingBeginEnd) {
aoqi@0 184 throw new DecodingException("UUDecoder: Missing begin");
aoqi@0 185 }
aoqi@0 186 // at EOF, fake it
aoqi@0 187 gotPrefix = true;
aoqi@0 188 gotEnd = true;
aoqi@0 189 break;
aoqi@0 190 }
aoqi@0 191 if (line.regionMatches(false, 0, "begin", 0, 5)) {
aoqi@0 192 try {
aoqi@0 193 mode = Integer.parseInt(line.substring(6,9));
aoqi@0 194 } catch (NumberFormatException ex) {
aoqi@0 195 if (!ignoreErrors) {
aoqi@0 196 throw new DecodingException(
aoqi@0 197 "UUDecoder: Error in mode: " + ex.toString());
aoqi@0 198 }
aoqi@0 199 }
aoqi@0 200 if (line.length() > 10) {
aoqi@0 201 name = line.substring(10);
aoqi@0 202 } else {
aoqi@0 203 if (!ignoreErrors) {
aoqi@0 204 throw new DecodingException(
aoqi@0 205 "UUDecoder: Missing name: " + line);
aoqi@0 206 }
aoqi@0 207 }
aoqi@0 208 gotPrefix = true;
aoqi@0 209 break;
aoqi@0 210 } else if (ignoreMissingBeginEnd && line.length() != 0) {
aoqi@0 211 int count = line.charAt(0);
aoqi@0 212 count = (count - ' ') & 0x3f;
aoqi@0 213 int need = ((count * 8)+5)/6;
aoqi@0 214 if (need == 0 || line.length() >= need + 1) {
aoqi@0 215 /*
aoqi@0 216 * Looks like a legitimate encoded line.
aoqi@0 217 * Pretend we saw the "begin" line and
aoqi@0 218 * save this line for later processing in
aoqi@0 219 * decode().
aoqi@0 220 */
aoqi@0 221 readAhead = line;
aoqi@0 222 gotPrefix = true; // fake it
aoqi@0 223 break;
aoqi@0 224 }
aoqi@0 225 }
aoqi@0 226 }
aoqi@0 227 }
aoqi@0 228
aoqi@0 229 private boolean decode() throws IOException {
aoqi@0 230
aoqi@0 231 if (gotEnd) {
aoqi@0 232 return false;
aoqi@0 233 }
aoqi@0 234 bufsize = 0;
aoqi@0 235 int count = 0;
aoqi@0 236 String line;
aoqi@0 237 for (;;) {
aoqi@0 238 /*
aoqi@0 239 * If we ignored a missing "begin", the first line
aoqi@0 240 * will be saved in readAhead.
aoqi@0 241 */
aoqi@0 242 if (readAhead != null) {
aoqi@0 243 line = readAhead;
aoqi@0 244 readAhead = null;
aoqi@0 245 } else {
aoqi@0 246 line = lin.readLine();
aoqi@0 247 }
aoqi@0 248
aoqi@0 249 /*
aoqi@0 250 * Improperly encoded data sometimes omits the zero length
aoqi@0 251 * line that starts with a space character, we detect the
aoqi@0 252 * following "end" line here.
aoqi@0 253 */
aoqi@0 254 if (line == null) {
aoqi@0 255 if (!ignoreMissingBeginEnd) {
aoqi@0 256 throw new DecodingException(
aoqi@0 257 "UUDecoder: Missing end at EOF");
aoqi@0 258 }
aoqi@0 259 gotEnd = true;
aoqi@0 260 return false;
aoqi@0 261 }
aoqi@0 262 if (line.equals("end")) {
aoqi@0 263 gotEnd = true;
aoqi@0 264 return false;
aoqi@0 265 }
aoqi@0 266 if (line.length() == 0) {
aoqi@0 267 continue;
aoqi@0 268 }
aoqi@0 269 count = line.charAt(0);
aoqi@0 270 if (count < ' ') {
aoqi@0 271 if (!ignoreErrors) {
aoqi@0 272 throw new DecodingException(
aoqi@0 273 "UUDecoder: Buffer format error");
aoqi@0 274 }
aoqi@0 275 continue;
aoqi@0 276 }
aoqi@0 277
aoqi@0 278 /*
aoqi@0 279 * The first character in a line is the number of original (not
aoqi@0 280 * the encoded atoms) characters in the line. Note that all the
aoqi@0 281 * code below has to handle the <SPACE> character that indicates
aoqi@0 282 * end of encoded stream.
aoqi@0 283 */
aoqi@0 284 count = (count - ' ') & 0x3f;
aoqi@0 285
aoqi@0 286 if (count == 0) {
aoqi@0 287 line = lin.readLine();
aoqi@0 288 if (line == null || !line.equals("end")) {
aoqi@0 289 if (!ignoreMissingBeginEnd) {
aoqi@0 290 throw new DecodingException(
aoqi@0 291 "UUDecoder: Missing End after count 0 line");
aoqi@0 292 }
aoqi@0 293 }
aoqi@0 294 gotEnd = true;
aoqi@0 295 return false;
aoqi@0 296 }
aoqi@0 297
aoqi@0 298 int need = ((count * 8)+5)/6;
aoqi@0 299 //System.out.println("count " + count + ", need " + need + ", len " + line.length());
aoqi@0 300 if (line.length() < need + 1) {
aoqi@0 301 if (!ignoreErrors) {
aoqi@0 302 throw new DecodingException(
aoqi@0 303 "UUDecoder: Short buffer error");
aoqi@0 304 }
aoqi@0 305 continue;
aoqi@0 306 }
aoqi@0 307
aoqi@0 308 // got a line we're committed to, break out and decode it
aoqi@0 309 break;
aoqi@0 310 }
aoqi@0 311
aoqi@0 312 int i = 1;
aoqi@0 313 byte a, b;
aoqi@0 314 /*
aoqi@0 315 * A correct uuencoder always encodes 3 characters at a time, even
aoqi@0 316 * if there aren't 3 characters left. But since some people out
aoqi@0 317 * there have broken uuencoders we handle the case where they
aoqi@0 318 * don't include these "unnecessary" characters.
aoqi@0 319 */
aoqi@0 320 while (bufsize < count) {
aoqi@0 321 // continue decoding until we get 'count' decoded chars
aoqi@0 322 a = (byte)((line.charAt(i++) - ' ') & 0x3f);
aoqi@0 323 b = (byte)((line.charAt(i++) - ' ') & 0x3f);
aoqi@0 324 buffer[bufsize++] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));
aoqi@0 325
aoqi@0 326 if (bufsize < count) {
aoqi@0 327 a = b;
aoqi@0 328 b = (byte)((line.charAt(i++) - ' ') & 0x3f);
aoqi@0 329 buffer[bufsize++] =
aoqi@0 330 (byte)(((a << 4) & 0xf0) | ((b >>> 2) & 0xf));
aoqi@0 331 }
aoqi@0 332
aoqi@0 333 if (bufsize < count) {
aoqi@0 334 a = b;
aoqi@0 335 b = (byte)((line.charAt(i++) - ' ') & 0x3f);
aoqi@0 336 buffer[bufsize++] = (byte)(((a << 6) & 0xc0) | (b & 0x3f));
aoqi@0 337 }
aoqi@0 338 }
aoqi@0 339 return true;
aoqi@0 340 }
aoqi@0 341
aoqi@0 342 /*** begin TEST program *****
aoqi@0 343 public static void main(String argv[]) throws Exception {
aoqi@0 344 FileInputStream infile = new FileInputStream(argv[0]);
aoqi@0 345 UUDecoderStream decoder = new UUDecoderStream(infile);
aoqi@0 346 int c;
aoqi@0 347
aoqi@0 348 try {
aoqi@0 349 while ((c = decoder.read()) != -1)
aoqi@0 350 System.out.write(c);
aoqi@0 351 System.out.flush();
aoqi@0 352 } catch (Exception e) {
aoqi@0 353 e.printStackTrace();
aoqi@0 354 }
aoqi@0 355 }
aoqi@0 356 **** end TEST program ****/
aoqi@0 357 }

mercurial