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

Fri, 04 Oct 2013 16:21:34 +0100

author
mkos
date
Fri, 04 Oct 2013 16:21:34 +0100
changeset 408
b0610cd08440
parent 0
373ffda63c9a
permissions
-rw-r--r--

8025054: Update JAX-WS RI integration to 2.2.9-b130926.1035
Reviewed-by: chegar

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

mercurial