You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by tk...@apache.org on 2001/02/06 13:33:40 UTC

cvs commit: xml-batik/sources/org/apache/batik/util/svg Base64Decoder.java Base64Encoder.java CharacterDecoder.java CharacterEncoder.java

tkormann    01/02/06 04:33:40

  Modified:    sources/org/apache/batik/ext/awt/image/renderable
                        RasterRable.java
               sources/org/apache/batik/svggen
                        ImageHandlerBase64Encoder.java
  Added:       sources/org/apache/batik/util Base64Decoder.java
                        Base64Encoder.java CharacterDecoder.java
                        CharacterEncoder.java
  Removed:     sources/org/apache/batik/util/svg Base64Decoder.java
                        Base64Encoder.java CharacterDecoder.java
                        CharacterEncoder.java
  Log:
  move base 64 encoder/decoder to the util package
  
  Revision  Changes    Path
  1.2       +15 -15    xml-batik/sources/org/apache/batik/ext/awt/image/renderable/RasterRable.java
  
  Index: RasterRable.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/renderable/RasterRable.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RasterRable.java	2001/01/24 05:39:34	1.1
  +++ RasterRable.java	2001/02/06 12:33:37	1.2
  @@ -9,7 +9,7 @@
   package org.apache.batik.ext.awt.image.renderable;
   
   import org.apache.batik.ext.awt.image.rendered.CachableRed;
  -import org.apache.batik.util.svg.Base64Decoder;
  +import org.apache.batik.util.Base64Decoder;
   
   import java.io.ByteArrayInputStream;
   import java.io.InputStream;
  @@ -52,7 +52,7 @@
    * RenderableImage world.
    *
    * @author <a href="mailto:Thomas.DeWeese@Kodak.com>Thomas DeWeese</a>
  - * @version $Id: RasterRable.java,v 1.1 2001/01/24 05:39:34 vhardy Exp $
  + * @version $Id: RasterRable.java,v 1.2 2001/02/06 12:33:37 tkormann Exp $
    */
   public class RasterRable
       extends    AbstractRable {
  @@ -147,7 +147,7 @@
        * Toolkit.createImage(...) function.
        * @param dataUrl the data url containing the complete base64
        *                encoded image data.
  -     * @param bounds The bounds of the image 
  +     * @param bounds The bounds of the image
        */
       public static Filter create(String dataUrl, Rectangle2D bounds){
           //
  @@ -196,7 +196,7 @@
               try {
                   Image img = createImage();
   
  -                if (img == null) 
  +                if (img == null)
                       // No Image was created, something is wrong...
                       return null;
   
  @@ -223,7 +223,7 @@
                           // isn't done yet, so try again.
                           continue;
                       };
  -                
  +
                       // All done!
                       break;
                   }
  @@ -240,10 +240,10 @@
   
                   g2d.drawImage(img, 0, 0, null);
                   g2d.dispose();
  -                
  +
                   return bi;
               }
  -            catch (Exception e) { 
  +            catch (Exception e) {
                   // Just catch everything.
               }
   
  @@ -269,7 +269,7 @@
                   g2d.dispose();
               }
   
  -            // Store the result in the RasterRable, and wake up 
  +            // Store the result in the RasterRable, and wake up
               // anyone who is waiting for our image..
               synchronized (this) {
                   src = RenderedImageCachableRed.wrap(bi);
  @@ -292,7 +292,7 @@
           /** The URL cache we are associated with */
           protected URLImageCache cache;
   
  -        /** 
  +        /**
            * Load an image from a url.
            * This will use the default URL cache.
            * @param url The url of the image to load (must be readable
  @@ -302,7 +302,7 @@
               this(url, URLImageCache.getDefaultCache());
           }
   
  -        /** 
  +        /**
            * Load an image from a url.
            * @param url The url of the image to load (must be readable
            *            with Toolkit.createImage(url).
  @@ -329,15 +329,15 @@
            */
           public BufferedImage load() {
               BufferedImage bi = cache.request(url);
  -            
  -            if (bi != null) 
  +
  +            if (bi != null)
                   return bi;
   
               bi = super.load();
   
               if (bi != null)
                   cache.put(url, bi); // Let other people use our work..
  -            else 
  +            else
                   // Something wrong, We Couldn't loda the image.
                   // This is debateable but I'm going to clear my entry
                   // rather than put the 'broken link' image here...
  @@ -363,7 +363,7 @@
            */
           public Base64ImageLoader(String base64Data) {
               this.base64Data = base64Data;
  -            this.start      = 0; 
  +            this.start      = 0;
               this.length     = base64Data.length();;
           }
   
  @@ -376,7 +376,7 @@
            */
           public Base64ImageLoader(String base64Data, int start, int length) {
               this.base64Data = base64Data;
  -            this.start      = start; 
  +            this.start      = start;
               this.length     = length;
           }
   
  
  
  
  1.6       +9 -9      xml-batik/sources/org/apache/batik/svggen/ImageHandlerBase64Encoder.java
  
  Index: ImageHandlerBase64Encoder.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/ImageHandlerBase64Encoder.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ImageHandlerBase64Encoder.java	2001/02/03 16:26:19	1.5
  +++ ImageHandlerBase64Encoder.java	2001/02/06 12:33:38	1.6
  @@ -16,7 +16,7 @@
   import java.net.*;
   
   import org.apache.batik.dom.util.XLinkSupport;
  -import org.apache.batik.util.svg.Base64Encoder;
  +import org.apache.batik.util.Base64Encoder;
   import org.apache.batik.ext.awt.image.codec.ImageEncoder;
   import org.apache.batik.ext.awt.image.codec.PNGImageEncoder;
   
  @@ -24,12 +24,12 @@
   
   /**
    * This implementation of ImageHandler encodes the input image as
  - * a PNG image first, then encodes the PNG image using Base64 
  + * a PNG image first, then encodes the PNG image using Base64
    * encoding and uses the result to encoder the image url using
    * the data protocol.
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: ImageHandlerBase64Encoder.java,v 1.5 2001/02/03 16:26:19 deweese Exp $
  + * @version $Id: ImageHandlerBase64Encoder.java,v 1.6 2001/02/06 12:33:38 tkormann Exp $
    * @see             org.apache.batik.svggen.SVGGraphics2D
    * @see             org.apache.batik.svggen.ImageHandler
    */
  @@ -58,7 +58,7 @@
               else{
                   BufferedImage buf = new BufferedImage(width, height,
                                                         BufferedImage.TYPE_INT_ARGB);
  -                
  +
                   Graphics2D g = buf.createGraphics();
                   g.drawImage(image, 0, 0, null);
                   g.dispose();
  @@ -75,7 +75,7 @@
           if(image == null){
               throw new IllegalArgumentException();
           }
  -        
  +
           RenderedImage r = image.createDefaultRendering();
           if(r == null){
               handleEmptyImage(imageElement);
  @@ -94,7 +94,7 @@
       /**
        * This version of handleHREF encodes the input image into a
        * PNG image whose bytes are then encoded with Base64. The
  -     * resulting encoded data is used to set the url on the 
  +     * resulting encoded data is used to set the url on the
        * input imageElement, using the data: protocol.
        */
       protected void handleHREF(RenderedImage image, Element imageElement){
  @@ -121,9 +121,9 @@
           // Finally, write out url
           //
           imageElement.setAttributeNS(XLinkSupport.XLINK_NAMESPACE_URI, ATTR_XLINK_HREF,
  -                                    DATA_PROTOCOL_PNG_PREFIX + 
  +                                    DATA_PROTOCOL_PNG_PREFIX +
                                       os.toString());
  -        
  +
       }
   
       public byte[] encodeImage(RenderedImage buf){
  @@ -171,7 +171,7 @@
           System.out.println();
           System.out.println("<svg width=\"450\" height=\"500\">");
           System.out.println("    <rect width=\"100%\" height=\"100%\" fill=\"yellow\" />");
  -        System.out.println("    <image x=\"30\" y=\"30\" xlink:href=\"" + imageElement.getAttributeNS(null, SVGSyntax.ATTR_XLINK_HREF) + "\" width=\"100\" height=\"100\" />");        
  +        System.out.println("    <image x=\"30\" y=\"30\" xlink:href=\"" + imageElement.getAttributeNS(null, SVGSyntax.ATTR_XLINK_HREF) + "\" width=\"100\" height=\"100\" />");
           System.out.println("</svg>");
           System.exit(0);
       }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/util/Base64Decoder.java
  
  Index: Base64Decoder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  import java.io.OutputStream;
  import java.io.InputStream;
  import java.io.PrintStream;
  import java.io.IOException;
  import java.io.EOFException;
  
  /**
   * This class implements a Base64 Character decoder as specified in RFC1113.
   * Unlike some other encoding schemes there is nothing in this encoding that
   * tells the decoder where a buffer starts or stops, so to use it you will need
   * to isolate your encoded data into a single chunk and then feed them
   * this decoder. The simplest way to do that is to read all of the encoded
   * data into a string and then use:
   * <pre>
   *      byte    mydata[];
   *      Base64Decoder base64 = new Base64Decoder();
   *
   *      mydata = base64.decodeBuffer(bufferString);
   * </pre>
   * This will decode the String in <i>bufferString</i> and give you an array
   * of bytes in the array <i>myData</i>.
   *
   * On errors, this class throws a IOException with the following detail
   * strings:
   * <pre>
   *    "Base64Decoder: Bad Padding byte (2)."
   *    "Base64Decoder: Bad Padding byte (1)."
   * </pre>
   *
   * @author <a href="vincent.hardy@eng.sun.com">Vincent Hardy</a>
   * @author      Chuck McManis
   * @version $Id: Base64Decoder.java,v 1.1 2001/02/06 12:33:38 tkormann Exp $
   *
   * @see         CharacterEncoder
   * @see         Base64Decoder
   */
  
  public class Base64Decoder extends CharacterDecoder {
  
      /** This class has 3 bytes per atom */
      int bytesPerAtom() {
          return (3);
      }
  
      /** This class has 48 bytes per encoded line */
      int bytesPerLine() {
          return (48);
      }
  
      /**
       * This character array provides the character to value map
       * based on RFC1113.
       */
      private final static char pem_array[] = {
          //       0   1   2   3   4   5   6   7
          'A','B','C','D','E','F','G','H', // 0
          'I','J','K','L','M','N','O','P', // 1
          'Q','R','S','T','U','V','W','X', // 2
          'Y','Z','a','b','c','d','e','f', // 3
          'g','h','i','j','k','l','m','n', // 4
          'o','p','q','r','s','t','u','v', // 5
          'w','x','y','z','0','1','2','3', // 6
          '4','5','6','7','8','9','+','/'  // 7
      };
  
      byte decode_buffer[] = new byte[4];
  
      /**
       * Decode one Base64 atom into 1, 2, or 3 bytes of data.
       */
      void decodeAtom(InputStream inStream, OutputStream outStream, int l) throws EOFException, IOException{
          int     i;
          byte    a = -1, b = -1, c = -1, d = -1;
          StringBuffer s = new StringBuffer(4);
  
          decode_buffer[0] = (byte) inStream.read();
          if (decode_buffer[0] == -1) {
              throw new EOFException();
          }
  
          // check to see if we caught the trailing end of a <CR><LF>
          if (decode_buffer[0] == '\n') {
              i = inStream.read(decode_buffer, 0, 4);
          } else {
              i = inStream.read(decode_buffer, 1, 3);
          }
          if (i == -1) {
              throw new EOFException();
          }
  
          for (i = 0; i < 64; i++) {
              if (decode_buffer[0] == pem_array[i]) {
                  a = (byte) i;
              }
              if (decode_buffer[1] == pem_array[i]) {
                  b = (byte) i;
              }
              if (decode_buffer[2] == pem_array[i]) {
                  c = (byte) i;
              }
              if (decode_buffer[3] == pem_array[i]) {
                  d = (byte) i;
              }
          }
          if ((l == 2) && (decode_buffer[3] != '=')) {
              throw new IOException("Base64Decoder: Bad Padding byte (2).");
          }
          if ((l == 1) &&
              ((decode_buffer[2] != '=') || (decode_buffer[3] != '='))) {
              throw new IOException("Base64Decoder: Bad Padding byte (1).");
          }
  
          for (i = 0; i < 4; i++) s.append((char) decode_buffer[i]);
          switch (l) {
          case 1:
              outStream.write( (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3)) );
              break;
          case 2:
              outStream.write( (byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)) );
              outStream.write( (byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)) );
              break;
          case 3:
              outStream.write( (byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)) );
              outStream.write( (byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)) );
              outStream.write( (byte) (((c << 6) & 0xc0) | (d  & 0x3f)) );
              break;
          }
          return;
      }
  
      /**
       * decodeLineSuffix in this decoder simply finds the [newLine] and
       * positions us past it.
       */
      void decodeLineSuffix(InputStream inStream, OutputStream outStream) throws EOFException, IOException{
          int c;
  
          while (true) {
              c = inStream.read();
              if (c == -1) {
                  throw new EOFException();
              }
              if ((c == '\n') || (c == '\r') || (c == ' ')) {
                  break;
              }
          }
      }
  }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/util/Base64Encoder.java
  
  Index: Base64Encoder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  import java.io.OutputStream;
  import java.io.InputStream;
  import java.io.PrintStream;
  import java.io.IOException;
  
  /**
   * This class implements a Base64 Character encoder as specified in RFC1113.
   * Unlike some other encoding schemes there is nothing in this encoding
   * that indicates where a buffer starts or ends.
   *
   * This means that the encoded text will simply start with the first line
   * of encoded text and end with the last line of encoded text.
   *
   * @author <a href="vincent.hardy@eng.sun.com">Vincent Hardy</a>
   * @author      Chuck McManis
   * @version $Id: Base64Encoder.java,v 1.1 2001/02/06 12:33:38 tkormann Exp $
   *
   * @see         CharacterEncoder
   * @see         Base64Decoder
   */
  
  public class Base64Encoder extends CharacterEncoder {
  
      /** this class encodes three bytes per atom. */
      int bytesPerAtom() {
          return (3);
      }
  
      /** this class encodes 48 bytes per line. */
      int bytesPerLine() {
          return (48);
      }
  
      /** This array maps the characters to their 6 bit values */
      private final static char pem_array[] = {
      //   0   1   2   3   4   5   6   7
          'A','B','C','D','E','F','G','H', // 0
          'I','J','K','L','M','N','O','P', // 1
          'Q','R','S','T','U','V','W','X', // 2
          'Y','Z','a','b','c','d','e','f', // 3
          'g','h','i','j','k','l','m','n', // 4
          'o','p','q','r','s','t','u','v', // 5
          'w','x','y','z','0','1','2','3', // 6
          '4','5','6','7','8','9','+','/'  // 7
      };
  
      /**
       * enocodeAtom - Take three bytes of input and encode it as 4
       * printable characters. Note that if the length in len is less
       * than three is encodes either one or two '=' signs to indicate
       * padding characters.
       */
      void encodeAtom(OutputStream outStream, byte data[], int offset, int len) throws IOException{
          byte a, b, c;
  
          if (len == 1) {
              a = data[offset];
              b = 0;
              c = 0;
              outStream.write(pem_array[(a >>> 2) & 0x3F]);
              outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
              outStream.write('=');
              outStream.write('=');
          } else if (len == 2) {
              a = data[offset];
              b = data[offset+1];
              c = 0;
              outStream.write(pem_array[(a >>> 2) & 0x3F]);
              outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
              outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
              outStream.write('=');
          } else {
              a = data[offset];
              b = data[offset+1];
              c = data[offset+2];
              outStream.write(pem_array[(a >>> 2) & 0x3F]);
              outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
              outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
              outStream.write(pem_array[c & 0x3F]);
          }
      }
  }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/util/CharacterDecoder.java
  
  Index: CharacterDecoder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  import java.io.OutputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.InputStream;
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.EOFException;
  
  /**
   * This class defines the decoding half of character encoders.
   * A character decoder is an algorithim for transforming 8 bit
   * binary data that has been encoded into text by a character
   * encoder, back into original binary form.
   *
   * The character encoders, in general, have been structured
   * around a central theme that binary data can be encoded into
   * text that has the form:
   *
   * <pre>
   *      [Buffer Prefix]
   *      [Line Prefix][encoded data atoms][Line Suffix]
   *      [Buffer Suffix]
   * </pre>
   *
   * Of course in the simplest encoding schemes, the buffer has no
   * distinct prefix of suffix, however all have some fixed relationship
   * between the text in an 'atom' and the binary data itself.
   *
   * In the CharacterEncoder and CharacterDecoder classes, one complete
   * chunk of data is referred to as a <i>buffer</i>. Encoded buffers
   * are all text, and decoded buffers (sometimes just referred to as
   * buffers) are binary octets.
   *
   * To create a custom decoder, you must, at a minimum,  overide three
   * abstract methods in this class.
   * <DL>
   * <DD>bytesPerAtom which tells the decoder how many bytes to
   * expect from decodeAtom
   * <DD>decodeAtom which decodes the bytes sent to it as text.
   * <DD>bytesPerLine which tells the encoder the maximum number of
   * bytes per line.
   * </DL>
   *
   * In general, the character decoders return error in the form of an
   * IOException. The syntax of the detail string is
   * <pre>
   *      DecoderClassName: Error message.
   * </pre>
   *
   * Several useful decoders have already been written and are
   * referenced in the See Also list below.
   *
   * @author <a href="maito:vincent.hardy@eng.sun.com">Vincent Hardy</a>
   * @author      Chuck McManis
   * @version $Id: CharacterDecoder.java,v 1.1 2001/02/06 12:33:38 tkormann Exp $
   *
   * @see         CharacterEncoder
   * @see         Base64Decoder
   */
  
  public abstract class CharacterDecoder {
  
      /** Return the number of bytes per atom of decoding */
      abstract int bytesPerAtom();
  
      /** Return the maximum number of bytes that can be encoded per line */
      abstract int bytesPerLine();
  
      /** decode the beginning of the buffer, by default this is a NOP. */
      void decodeBufferPrefix(InputStream aStream, OutputStream bStream) { }
  
      /** decode the buffer suffix, again by default it is a NOP. */
      void decodeBufferSuffix(InputStream aStream, OutputStream bStream) {}
  
      /**
       * This method should return, if it knows, the number of bytes
       * that will be decoded. Many formats such as uuencoding provide
       * this information. By default we return the maximum bytes that
       * could have been encoded on the line.
       */
      int decodeLinePrefix(InputStream aStream, OutputStream bStream) {
          return (bytesPerLine());
      }
  
      /**
       * This method post processes the line, if there are error detection
       * or correction codes in a line, they are generally processed by
       * this method. The simplest version of this method looks for the
       * (newline) character.
       */
      abstract void decodeLineSuffix(InputStream aStream, OutputStream bStream) throws EOFException, IOException;
  
      /**
       * This method does an actual decode. It takes the decoded bytes and
       * writes them to the OuputStream. The integer <i>l</i> tells the
       * method how many bytes are required. This is always <= bytesPerAtom().
       */
      abstract void decodeAtom(InputStream aStream, OutputStream bStream, int l) throws IOException, EOFException;
  
      /**
       * Decode the text from the InputStream and write the decoded
       * octets to the OutputStream. This method runs until the stream
       * is exhausted.
       * @exception RuntimeException An error has occured while decoding
       * @exception EOFException The input stream is unexpectedly out of data
       */
      public void decodeBuffer(InputStream aStream, OutputStream bStream) throws IOException{
          int     i;
  
          decodeBufferPrefix(aStream, bStream);
          while (true) {
              int length;
  
              try {
                  length = decodeLinePrefix(aStream, bStream);
                  for (i = 0; (i+bytesPerAtom()) < length; i += bytesPerAtom()) {
                      decodeAtom(aStream, bStream, bytesPerAtom());
                  }
                  if ((i + bytesPerAtom()) == length) {
                      decodeAtom(aStream, bStream, bytesPerAtom());
                  } else {
                      decodeAtom(aStream, bStream, (i + bytesPerAtom()) - length);
                  }
                  decodeLineSuffix(aStream, bStream);
              }catch(EOFException e){
                  // e.printStackTrace();
                  break;
              }
          }
          decodeBufferSuffix(aStream, bStream);
      }
  
      /**
       * Alternate decode interface that takes a String containing the encoded
       * buffer and returns a byte array containing the data.
       * @exception IOException An error has occured while decoding
       */
      public byte[] decodeBuffer(String inputString) throws IOException{
          ByteArrayInputStream inStream;
          ByteArrayOutputStream outStream;
  
          byte[] inputBuffer = inputString.getBytes();
          inStream = new ByteArrayInputStream(inputBuffer);
          outStream = new ByteArrayOutputStream();
          decodeBuffer(inStream, outStream);
          return (outStream.toByteArray());
      }
  
      /**
       * Decode the contents of the inputstream into a buffer.
       */
      public byte[] decodeBuffer(InputStream in) throws IOException {
          ByteArrayOutputStream outStream = new ByteArrayOutputStream();
          decodeBuffer(in, outStream);
          return (outStream.toByteArray());
      }
  }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/util/CharacterEncoder.java
  
  Index: CharacterEncoder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  import java.io.InputStream;
  import java.io.ByteArrayInputStream;
  import java.io.OutputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.PrintStream;
  import java.io.IOException;
  
  /**
   * This class defines the encoding half of character encoders.
   * A character encoder is an algorithim for transforming 8 bit binary
   * data into text (generally 7 bit ASCII or 8 bit ISO-Latin-1 text)
   * for transmition over text channels such as e-mail and network news.
   *
   * The character encoders have been structured around a central theme
   * that, in general, the encoded text has the form:
   *
   * <pre>
   *      [Buffer Prefix]
   *      [Line Prefix][encoded data atoms][Line Suffix]
   *      [Buffer Suffix]
   * </pre>
   *
   * In the CharacterEncoder and CharacterDecoder classes, one complete
   * chunk of data is referred to as a <i>buffer</i>. Encoded buffers
   * are all text, and decoded buffers (sometimes just referred to as
   * buffers) are binary octets.
   *
   * To create a custom encoder, you must, at a minimum,  overide three
   * abstract methods in this class.
   * <DL>
   * <DD>bytesPerAtom which tells the encoder how many bytes to
   * send to encodeAtom
   * <DD>encodeAtom which encodes the bytes sent to it as text.
   * <DD>bytesPerLine which tells the encoder the maximum number of
   * bytes per line.
   * </DL>
   *
   * Several useful encoders have already been written and are
   * referenced in the See Also list below.
   *
   * @author <a href="vincent.hardy@eng.sun.com">Vincent Hardy</a>
   * @author      Chuck McManis
   * @version $Id: CharacterEncoder.java,v 1.1 2001/02/06 12:33:38 tkormann Exp $
   *
   * @see         CharacterDecoder
   * @see         Base64Encoder
   */
  
  public abstract class CharacterEncoder {
  
      /** Stream that understands "printing" */
      protected PrintStream pStream;
  
      /** Return the number of bytes per atom of encoding */
      abstract int bytesPerAtom();
  
      /** Return the number of bytes that can be encoded per line */
      abstract int bytesPerLine();
  
      /**
       * Encode the prefix for the entire buffer. By default is simply
       * opens the PrintStream for use by the other functions.
       */
      void encodeBufferPrefix(OutputStream aStream) {
          pStream = new PrintStream(aStream);
      }
  
      /**
       * Encode the suffix for the entire buffer.
       */
      void encodeBufferSuffix(OutputStream aStream) { }
  
      /**
       * Encode the prefix that starts every output line.
       */
      void encodeLinePrefix(OutputStream aStream, int aLength) { }
  
      /**
       * Encode the suffix that ends every output line. By default
       * this method just prints a <newline> into the output stream.
       */
      void encodeLineSuffix(OutputStream aStream) {
          pStream.println();
      }
  
      /** Encode one "atom" of information into characters. */
      abstract void encodeAtom(OutputStream aStream, byte someBytes[],
                               int anOffset, int aLength) throws IOException;
  
      /**
       * Encode bytes from the input stream, and write them as text characters
       * to the output stream. This method will run until it exhausts the
       * input stream.
       */
      public void encodeBuffer(InputStream inStream, OutputStream outStream) throws IOException{
          int     j;
          int     numBytes;
          byte    tmpbuffer[] = new byte[bytesPerLine()];
  
          encodeBufferPrefix(outStream);
  
          while (true) {
              numBytes = inStream.read(tmpbuffer);
              if (numBytes == -1) {
                  break;
              }
              encodeLinePrefix(outStream, numBytes);
              for (j = 0; j < numBytes; j += bytesPerAtom()) {
                  if ((j + bytesPerAtom()) <= numBytes) {
                      encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
                  } else {
                      encodeAtom(outStream, tmpbuffer, j, tmpbuffer.length - j);
                  }
              }
              encodeLineSuffix(outStream);
              if (numBytes < bytesPerLine()) {
                  break;
              }
          }
          encodeBufferSuffix(outStream);
      }
  
      /**
       * Encode the buffer in <i>aBuffer</i> and write the encoded
       * result to the OutputStream <i>aStream</i>.
       */
      public void encodeBuffer(byte aBuffer[], OutputStream aStream) throws IOException{
          ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
          encodeBuffer(inStream, aStream);
      }
  
      /**
       * A 'streamless' version of encode that simply takes a buffer of
       * bytes and returns a string containing the encoded buffer.
       */
      public String encodeBuffer(byte aBuffer[]) throws IOException{
          ByteArrayOutputStream   outStream = new ByteArrayOutputStream();
          ByteArrayInputStream    inStream = new ByteArrayInputStream(aBuffer);
          encodeBuffer(inStream, outStream);
          return (outStream.toString());
      }
  
  }