home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / win95 / sieciowe / hotja32.lzh / hotjava / classsrc / java / util / uudecoder.java < prev    next >
Text File  |  1995-08-11  |  7KB  |  248 lines

  1. /*
  2.  * @(#)UUDecoder.java    1.1 95/03/16 Chuck McManis
  3.  *
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19. package java.util;
  20.  
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.io.PrintStream;
  24.  
  25. /**
  26.  * This class implements a Berkeley uu character decoder. This decoder
  27.  * was made famous by the uudecode program.
  28.  *
  29.  * The basic character coding is algorithmic, taking 6 bits of binary
  30.  * data and adding it to an ASCII ' ' (space) character. This converts
  31.  * these six bits into a printable representation. Note that it depends
  32.  * on the ASCII character encoding standard for english. Groups of three
  33.  * bytes are converted into 4 characters by treating the three bytes
  34.  * a four 6 bit groups, group 1 is byte 1's most significant six bits,
  35.  * group 2 is byte 1's least significant two bits plus byte 2's four
  36.  * most significant bits. etc.
  37.  *
  38.  * In this encoding, the buffer prefix is:
  39.  * <pre>
  40.  *     begin [mode] [filename]
  41.  * </pre>
  42.  *
  43.  * This is followed by one or more lines of the form:
  44.  * <pre>
  45.  *    (len)(data)(data)(data) ...
  46.  * </pre>
  47.  * where (len) is the number of bytes on this line. Note that groupings
  48.  * are always four characters, even if length is not a multiple of three
  49.  * bytes. When less than three characters are encoded, the values of the
  50.  * last remaining bytes is undefined and should be ignored.
  51.  *
  52.  * The last line of data in a uuencoded buffer is represented by a single
  53.  * space character. This is translated by the decoding engine to a line
  54.  * length of zero. This is immediately followed by a line which contains
  55.  * the word 'end[newline]'
  56.  *
  57.  * If an error is encountered during decoding this class throws a
  58.  * CEFormatException. The specific detail messages are:
  59.  *
  60.  * <pre>
  61.  *    "UUDecoder: No begin line."
  62.  *    "UUDecoder: Malformed begin line."
  63.  *    "UUDecoder: Short Buffer."
  64.  *    "UUDecoder: Bad Line Length."
  65.  *    "UUDecoder: Missing 'end' line."
  66.  * </pre>
  67.  *
  68.  * @version     1.1, 16 Mar 1995
  69.  * @author      Chuck McManis
  70.  * @see        CharacterDecoder
  71.  * @see        UUEncoder
  72.  */
  73. public class UUDecoder extends CharacterDecoder {
  74.  
  75.     /** 
  76.      * This string contains the name that was in the buffer being decoded.
  77.      */
  78.     public String bufferName;
  79.  
  80.     /**
  81.      * Represents UNIX(tm) mode bits. Generally three octal digits 
  82.      * representing read, write, and execute permission of the owner, 
  83.      * group owner, and  others. They should be interpreted as the bit groups:
  84.      * <pre>
  85.      * (owner) (group) (others)
  86.      *    rwx      rwx     rwx     (r = read, w = write, x = execute)
  87.      *</pre>
  88.      *
  89.      */
  90.     public int mode;
  91.  
  92.  
  93.     /**
  94.      * UU encoding specifies 3 bytes per atom.
  95.      */
  96.     int bytesPerAtom() {
  97.     return (3);    
  98.     }
  99.  
  100.     /**
  101.      * All UU lines have 45 bytes on them, for line length of 15*4+1 or 61
  102.      * characters per line.
  103.      */
  104.     int bytesPerLine() {
  105.     return (45);
  106.     }
  107.  
  108.     /** This is used to decode the atoms */
  109.     private byte decoderBuffer[] = new byte[4];
  110.  
  111.     /**
  112.      * Decode a UU atom. Note that if l is less than 3 we don't write
  113.      * the extra bits, however the encoder always encodes 4 character
  114.      * groups even when they are not needed.
  115.      */
  116.     void decodeAtom(InputStream inStream, OutputStream outStream, int l) {
  117.     int i, c1, c2, c3, c4;
  118.     int a, b, c;
  119.     StringBuffer x = new StringBuffer();
  120.  
  121.     for (i = 0; i < 4; i++) {
  122.         c1 = inStream.read();
  123.         if (c1 == -1) {
  124.             throw new CEStreamExhausted();
  125.         }
  126.         x.appendChar(c1);
  127.         decoderBuffer[i] = (byte) ((c1 - ' ') & 0x3f);
  128.     }
  129.     a = ((decoderBuffer[0] << 2) & 0xfc) | ((decoderBuffer[1] >>> 4) & 3);
  130.     b = ((decoderBuffer[1] << 4) & 0xf0) | ((decoderBuffer[2] >>> 2) & 0xf);
  131.     c = ((decoderBuffer[2] << 6) & 0xc0) | (decoderBuffer[3] & 0x3f);
  132.     outStream.write((byte)(a & 0xff));
  133.     if (l > 1) {
  134.         outStream.write((byte)( b & 0xff));
  135.     }
  136.     if (l > 2) {
  137.         outStream.write((byte)(c&0xff));
  138.     }
  139.     }
  140.     
  141.     /**
  142.      * For uuencoded buffers, the data begins with a line of the form:
  143.      *         begin MODE FILENAME
  144.      * This line always starts in column 1.
  145.      */
  146.     void decodeBufferPrefix(InputStream inStream, OutputStream outStream) {
  147.     int    c;
  148.     StringBuffer q = new StringBuffer(32);
  149.     String r;
  150.     boolean sawNewLine;
  151.  
  152.     /*
  153.      * This works by ripping through the buffer until it finds a 'begin'
  154.      * line or the end of the buffer.
  155.      */
  156.     sawNewLine = true;
  157.     while (true) {
  158.         c = inStream.read();
  159.         if (c == -1) {
  160.         throw new CEFormatException("UUDecoder: No begin line.");
  161.         }
  162.         if ((c == 'b')  && sawNewLine){
  163.         c = inStream.read();
  164.         if (c == 'e') {
  165.             break;
  166.         }
  167.         }
  168.         sawNewLine = (c == '\n') || (c == '\r');
  169.     }
  170.     
  171.     /* 
  172.      * Now we think its begin, (we've seen ^be) so verify it here.
  173.          */
  174.     while ((c != '\n') && (c != '\r')) {
  175.         c = inStream.read();
  176.         if (c == -1) {
  177.         throw new CEFormatException("UUDecoder: No begin line.");
  178.         }
  179.         if ((c != '\n') && (c != '\r')) {
  180.         q.appendChar(c);
  181.         }
  182.     }
  183.     r = q.toString();
  184.     if (r.indexOf(' ') != 3) {
  185.         throw new CEFormatException("UUDecoder: Malformed begin line.");
  186.     }
  187.     mode = Integer.parseInt(r.substring(4,7));
  188.     bufferName = r.substring(r.indexOf(' ',6)+1);
  189.     }
  190.  
  191.     /**
  192.      * In uuencoded buffers, encoded lines start with a character that
  193.      * represents the number of bytes encoded in this line. The last
  194.      * line of input is always a line that starts with a single space
  195.      * character, which would be a zero length line.
  196.      */ 
  197.     int decodeLinePrefix(InputStream inStream, OutputStream outStream) {
  198.     int    c;
  199.  
  200.     c = inStream.read();
  201.     if (c == ' ') {
  202.         c = inStream.read(); /* discard the trailing <newline> */
  203.         throw new CEStreamExhausted();
  204.     } else if (c == -1) {
  205.         throw new CEFormatException("UUDecoder: Short Buffer.");
  206.     }
  207.     
  208.     c = (c - ' ') & 0x3f;
  209.     if (c > bytesPerLine()) {
  210.         throw new CEFormatException("UUDecoder: Bad Line Length.");
  211.     }
  212.     return (c);
  213.     }
  214.  
  215.  
  216.     /**
  217.      * Find the end of the line for the next operation.
  218.      */
  219.     void decodeLineSuffix(InputStream inStream, OutputStream outStream) { 
  220.     int c;
  221.     while (true) {
  222.         c = inStream.read();
  223.         if (c == -1) {
  224.         throw new CEStreamExhausted();
  225.         }
  226.         if (c == '\n') {
  227.         break;
  228.         }
  229.     }
  230.     }
  231.  
  232.     /**
  233.      * UUencoded files have a buffer suffix which consists of the word
  234.      * end. This line should immediately follow the line with a single
  235.      * space in it.
  236.      */
  237.     void decodeBufferSuffix(InputStream inStream, OutputStream outStream){
  238.     int    c;
  239.  
  240.     c = inStream.read(decoderBuffer);
  241.     if ((decoderBuffer[0] != 'e') || (decoderBuffer[1] != 'n') ||
  242.         (decoderBuffer[2] != 'd')) {
  243.         throw new CEFormatException("UUDecoder: Missing 'end' line.");
  244.     }
  245.     }
  246.      
  247. }
  248.