jdk/src/java.base/share/classes/sun/misc/UUDecoder.java
changeset 34746 be3fcc9b7a78
parent 34745 995895614a53
parent 34741 6f034bebd711
child 34748 3b2cde99bd99
equal deleted inserted replaced
34745:995895614a53 34746:be3fcc9b7a78
     1 /*
       
     2  * Copyright (c) 1995, 2001, 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  */
       
    25 package sun.misc;
       
    26 
       
    27 import java.io.PushbackInputStream;
       
    28 import java.io.OutputStream;
       
    29 import java.io.PrintStream;
       
    30 import 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  */
       
    79 public 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         StringBuilder x = new StringBuilder();
       
   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         StringBuilder q = new StringBuilder(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 }