Save This Page
Home » openjdk-7 » sun » misc » [javadoc | source]
    1   /*
    2    * Copyright (c) 1995, 2005, 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   
   26   package sun.misc;
   27   
   28   import java.io.InputStream;
   29   import java.io.ByteArrayInputStream;
   30   import java.io.OutputStream;
   31   import java.io.ByteArrayOutputStream;
   32   import java.io.PrintStream;
   33   import java.io.IOException;
   34   import java.nio.ByteBuffer;
   35   
   36   
   37   /**
   38    * This class defines the encoding half of character encoders.
   39    * A character encoder is an algorithim for transforming 8 bit binary
   40    * data into text (generally 7 bit ASCII or 8 bit ISO-Latin-1 text)
   41    * for transmition over text channels such as e-mail and network news.
   42    *
   43    * The character encoders have been structured around a central theme
   44    * that, in general, the encoded text has the form:
   45    *
   46    * <pre>
   47    *      [Buffer Prefix]
   48    *      [Line Prefix][encoded data atoms][Line Suffix]
   49    *      [Buffer Suffix]
   50    * </pre>
   51    *
   52    * In the CharacterEncoder and CharacterDecoder classes, one complete
   53    * chunk of data is referred to as a <i>buffer</i>. Encoded buffers
   54    * are all text, and decoded buffers (sometimes just referred to as
   55    * buffers) are binary octets.
   56    *
   57    * To create a custom encoder, you must, at a minimum,  overide three
   58    * abstract methods in this class.
   59    * <DL>
   60    * <DD>bytesPerAtom which tells the encoder how many bytes to
   61    * send to encodeAtom
   62    * <DD>encodeAtom which encodes the bytes sent to it as text.
   63    * <DD>bytesPerLine which tells the encoder the maximum number of
   64    * bytes per line.
   65    * </DL>
   66    *
   67    * Several useful encoders have already been written and are
   68    * referenced in the See Also list below.
   69    *
   70    * @author      Chuck McManis
   71    * @see         CharacterDecoder;
   72    * @see         UCEncoder
   73    * @see         UUEncoder
   74    * @see         BASE64Encoder
   75    */
   76   public abstract class CharacterEncoder {
   77   
   78       /** Stream that understands "printing" */
   79       protected PrintStream pStream;
   80   
   81       /** Return the number of bytes per atom of encoding */
   82       abstract protected int bytesPerAtom();
   83   
   84       /** Return the number of bytes that can be encoded per line */
   85       abstract protected int bytesPerLine();
   86   
   87       /**
   88        * Encode the prefix for the entire buffer. By default is simply
   89        * opens the PrintStream for use by the other functions.
   90        */
   91       protected void encodeBufferPrefix(OutputStream aStream) throws IOException {
   92           pStream = new PrintStream(aStream);
   93       }
   94   
   95       /**
   96        * Encode the suffix for the entire buffer.
   97        */
   98       protected void encodeBufferSuffix(OutputStream aStream) throws IOException {
   99       }
  100   
  101       /**
  102        * Encode the prefix that starts every output line.
  103        */
  104       protected void encodeLinePrefix(OutputStream aStream, int aLength)
  105       throws IOException {
  106       }
  107   
  108       /**
  109        * Encode the suffix that ends every output line. By default
  110        * this method just prints a <newline> into the output stream.
  111        */
  112       protected void encodeLineSuffix(OutputStream aStream) throws IOException {
  113           pStream.println();
  114       }
  115   
  116       /** Encode one "atom" of information into characters. */
  117       abstract protected void encodeAtom(OutputStream aStream, byte someBytes[],
  118                   int anOffset, int aLength) throws IOException;
  119   
  120       /**
  121        * This method works around the bizarre semantics of BufferedInputStream's
  122        * read method.
  123        */
  124       protected int readFully(InputStream in, byte buffer[])
  125           throws java.io.IOException {
  126           for (int i = 0; i < buffer.length; i++) {
  127               int q = in.read();
  128               if (q == -1)
  129                   return i;
  130               buffer[i] = (byte)q;
  131           }
  132           return buffer.length;
  133       }
  134   
  135       /**
  136        * Encode bytes from the input stream, and write them as text characters
  137        * to the output stream. This method will run until it exhausts the
  138        * input stream, but does not print the line suffix for a final
  139        * line that is shorter than bytesPerLine().
  140        */
  141       public void encode(InputStream inStream, OutputStream outStream)
  142           throws IOException {
  143           int     j;
  144           int     numBytes;
  145           byte    tmpbuffer[] = new byte[bytesPerLine()];
  146   
  147           encodeBufferPrefix(outStream);
  148   
  149           while (true) {
  150               numBytes = readFully(inStream, tmpbuffer);
  151               if (numBytes == 0) {
  152                   break;
  153               }
  154               encodeLinePrefix(outStream, numBytes);
  155               for (j = 0; j < numBytes; j += bytesPerAtom()) {
  156   
  157                   if ((j + bytesPerAtom()) <= numBytes) {
  158                       encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
  159                   } else {
  160                       encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
  161                   }
  162               }
  163               if (numBytes < bytesPerLine()) {
  164                   break;
  165               } else {
  166                   encodeLineSuffix(outStream);
  167               }
  168           }
  169           encodeBufferSuffix(outStream);
  170       }
  171   
  172       /**
  173        * Encode the buffer in <i>aBuffer</i> and write the encoded
  174        * result to the OutputStream <i>aStream</i>.
  175        */
  176       public void encode(byte aBuffer[], OutputStream aStream)
  177       throws IOException {
  178           ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
  179           encode(inStream, aStream);
  180       }
  181   
  182       /**
  183        * A 'streamless' version of encode that simply takes a buffer of
  184        * bytes and returns a string containing the encoded buffer.
  185        */
  186       public String encode(byte aBuffer[]) {
  187           ByteArrayOutputStream   outStream = new ByteArrayOutputStream();
  188           ByteArrayInputStream    inStream = new ByteArrayInputStream(aBuffer);
  189           String retVal = null;
  190           try {
  191               encode(inStream, outStream);
  192               // explicit ascii->unicode conversion
  193               retVal = outStream.toString("8859_1");
  194           } catch (Exception IOException) {
  195               // This should never happen.
  196               throw new Error("CharacterEncoder.encode internal error");
  197           }
  198           return (retVal);
  199       }
  200   
  201       /**
  202        * Return a byte array from the remaining bytes in this ByteBuffer.
  203        * <P>
  204        * The ByteBuffer's position will be advanced to ByteBuffer's limit.
  205        * <P>
  206        * To avoid an extra copy, the implementation will attempt to return the
  207        * byte array backing the ByteBuffer.  If this is not possible, a
  208        * new byte array will be created.
  209        */
  210       private byte [] getBytes(ByteBuffer bb) {
  211           /*
  212            * This should never return a BufferOverflowException, as we're
  213            * careful to allocate just the right amount.
  214            */
  215           byte [] buf = null;
  216   
  217           /*
  218            * If it has a usable backing byte buffer, use it.  Use only
  219            * if the array exactly represents the current ByteBuffer.
  220            */
  221           if (bb.hasArray()) {
  222               byte [] tmp = bb.array();
  223               if ((tmp.length == bb.capacity()) &&
  224                       (tmp.length == bb.remaining())) {
  225                   buf = tmp;
  226                   bb.position(bb.limit());
  227               }
  228           }
  229   
  230           if (buf == null) {
  231               /*
  232                * This class doesn't have a concept of encode(buf, len, off),
  233                * so if we have a partial buffer, we must reallocate
  234                * space.
  235                */
  236               buf = new byte[bb.remaining()];
  237   
  238               /*
  239                * position() automatically updated
  240                */
  241               bb.get(buf);
  242           }
  243   
  244           return buf;
  245       }
  246   
  247       /**
  248        * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
  249        * result to the OutputStream <i>aStream</i>.
  250        * <P>
  251        * The ByteBuffer's position will be advanced to ByteBuffer's limit.
  252        */
  253       public void encode(ByteBuffer aBuffer, OutputStream aStream)
  254           throws IOException {
  255           byte [] buf = getBytes(aBuffer);
  256           encode(buf, aStream);
  257       }
  258   
  259       /**
  260        * A 'streamless' version of encode that simply takes a ByteBuffer
  261        * and returns a string containing the encoded buffer.
  262        * <P>
  263        * The ByteBuffer's position will be advanced to ByteBuffer's limit.
  264        */
  265       public String encode(ByteBuffer aBuffer) {
  266           byte [] buf = getBytes(aBuffer);
  267           return encode(buf);
  268       }
  269   
  270       /**
  271        * Encode bytes from the input stream, and write them as text characters
  272        * to the output stream. This method will run until it exhausts the
  273        * input stream. It differs from encode in that it will add the
  274        * line at the end of a final line that is shorter than bytesPerLine().
  275        */
  276       public void encodeBuffer(InputStream inStream, OutputStream outStream)
  277           throws IOException {
  278           int     j;
  279           int     numBytes;
  280           byte    tmpbuffer[] = new byte[bytesPerLine()];
  281   
  282           encodeBufferPrefix(outStream);
  283   
  284           while (true) {
  285               numBytes = readFully(inStream, tmpbuffer);
  286               if (numBytes == 0) {
  287                   break;
  288               }
  289               encodeLinePrefix(outStream, numBytes);
  290               for (j = 0; j < numBytes; j += bytesPerAtom()) {
  291                   if ((j + bytesPerAtom()) <= numBytes) {
  292                       encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
  293                   } else {
  294                       encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
  295                   }
  296               }
  297               encodeLineSuffix(outStream);
  298               if (numBytes < bytesPerLine()) {
  299                   break;
  300               }
  301           }
  302           encodeBufferSuffix(outStream);
  303       }
  304   
  305       /**
  306        * Encode the buffer in <i>aBuffer</i> and write the encoded
  307        * result to the OutputStream <i>aStream</i>.
  308        */
  309       public void encodeBuffer(byte aBuffer[], OutputStream aStream)
  310       throws IOException {
  311           ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
  312           encodeBuffer(inStream, aStream);
  313       }
  314   
  315       /**
  316        * A 'streamless' version of encode that simply takes a buffer of
  317        * bytes and returns a string containing the encoded buffer.
  318        */
  319       public String encodeBuffer(byte aBuffer[]) {
  320           ByteArrayOutputStream   outStream = new ByteArrayOutputStream();
  321           ByteArrayInputStream    inStream = new ByteArrayInputStream(aBuffer);
  322           try {
  323               encodeBuffer(inStream, outStream);
  324           } catch (Exception IOException) {
  325               // This should never happen.
  326               throw new Error("CharacterEncoder.encodeBuffer internal error");
  327           }
  328           return (outStream.toString());
  329       }
  330   
  331       /**
  332        * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
  333        * result to the OutputStream <i>aStream</i>.
  334        * <P>
  335        * The ByteBuffer's position will be advanced to ByteBuffer's limit.
  336        */
  337       public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
  338           throws IOException {
  339           byte [] buf = getBytes(aBuffer);
  340           encodeBuffer(buf, aStream);
  341       }
  342   
  343       /**
  344        * A 'streamless' version of encode that simply takes a ByteBuffer
  345        * and returns a string containing the encoded buffer.
  346        * <P>
  347        * The ByteBuffer's position will be advanced to ByteBuffer's limit.
  348        */
  349       public String encodeBuffer(ByteBuffer aBuffer) {
  350           byte [] buf = getBytes(aBuffer);
  351           return encodeBuffer(buf);
  352       }
  353   
  354   }

Save This Page
Home » openjdk-7 » sun » misc » [javadoc | source]