QP Decoder Stream : Base64 « Development Class « Java






QP Decoder Stream

      
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * @(#)QPDecoderStream.java 1.11 07/05/04
 */


import java.io.*;

/**
 * This class implements a QP Decoder. It is implemented as
 * a FilterInputStream, so one can just wrap this class around
 * any input stream and read bytes from this filter. The decoding
 * is done as the bytes are read out.
 * 
 * @author John Mani
 */

public class QPDecoderStream extends FilterInputStream {
    protected byte[] ba = new byte[2];
    protected int spaces = 0;

    /**
     * Create a Quoted Printable decoder that decodes the specified 
     * input stream.
     * @param in        the input stream
     */
    public QPDecoderStream(InputStream in) {
  super(new PushbackInputStream(in, 2)); // pushback of size=2
    }

    /**
     * Read the next decoded byte from this input stream. The byte
     * is returned as an <code>int</code> in the range <code>0</code>
     * to <code>255</code>. If no byte is available because the end of
     * the stream has been reached, the value <code>-1</code> is returned.
     * This method blocks until input data is available, the end of the
     * stream is detected, or an exception is thrown.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read() throws IOException {
  if (spaces > 0) {
      // We have cached space characters, return one
      spaces--;
      return ' ';
  }
  
  int c = in.read();

  if (c == ' ') { 
      // Got space, keep reading till we get a non-space char
      while ((c = in.read()) == ' ')
    spaces++;

      if (c == '\r' || c == '\n' || c == -1)
    // If the non-space char is CR/LF/EOF, the spaces we got
        // so far is junk introduced during transport. Junk 'em.
    spaces = 0;
          else {
    // The non-space char is NOT CR/LF, the spaces are valid.
    ((PushbackInputStream)in).unread(c);
    c = ' ';
      }
      return c; // return either <SPACE> or <CR/LF>
  }
  else if (c == '=') {
      // QP Encoded atom. Decode the next two bytes
      int a = in.read();

      if (a == '\n') {
    /* Hmm ... not really confirming QP encoding, but lets
     * allow this as a LF terminated encoded line .. and
     * consider this a soft linebreak and recurse to fetch 
     * the next char.
     */
    return read();
      } else if (a == '\r') {
    // Expecting LF. This forms a soft linebreak to be ignored.
    int b = in.read();
    if (b != '\n') 
        /* Not really confirming QP encoding, but
         * lets allow this as well.
         */
        ((PushbackInputStream)in).unread(b);
    return read();
      } else if (a == -1) {
      // Not valid QP encoding, but we be nice and tolerant here !
    return -1;
      } else {
    ba[0] = (byte)a;
    ba[1] = (byte)in.read();
    try {
        return ASCIIUtility.parseInt(ba, 0, 2, 16);
    } catch (NumberFormatException nex) {
        /*
        System.err.println(
          "Illegal characters in QP encoded stream: " + 
          ASCIIUtility.toString(ba, 0, 2)
        );
        */

        ((PushbackInputStream)in).unread(ba);
        return c;
    }
      }
  }
  return c;
    }

    /**
     * Reads up to <code>len</code> decoded bytes of data from this input stream
     * into an array of bytes. This method blocks until some input is
     * available.
     * <p>
     *
     * @param      buf   the buffer into which the data is read.
     * @param      off   the start offset of the data.
     * @param      len   the maximum number of bytes read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the stream has been reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read(byte[] buf, int off, int len) throws IOException {
  int i, c;
  for (i = 0; i < len; i++) {
      if ((c = read()) == -1) {
    if (i == 0) // At end of stream, so we should
        i = -1; // return -1 , NOT 0.
    break;
      }
      buf[off+i] = (byte)c;
  }
        return i;
    }

    /**
     * Tests if this input stream supports marks. Currently this class
     * does not support marks
     */
    public boolean markSupported() {
  return false;
    }

    /**
     * Returns the number of bytes that can be read from this input
     * stream without blocking. The QP algorithm does not permit
     * a priori knowledge of the number of bytes after decoding, so
     * this method just invokes the <code>available</code> method
     * of the original input stream.
     */
    public int available() throws IOException {
  // This is bogus ! We don't really know how much
  // bytes are available *after* decoding
  return in.available();
    }

    /**** begin TEST program
    public static void main(String argv[]) throws Exception {
        FileInputStream infile = new FileInputStream(argv[0]);
        QPDecoderStream decoder = new QPDecoderStream(infile);
        int c;
 
        while ((c = decoder.read()) != -1)
            System.out.print((char)c);
        System.out.println();
    }
    *** end TEST program ****/
}
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * @(#)ASCIIUtility.java  1.11 07/05/04
 */
 class ASCIIUtility {

    // Private constructor so that this class is not instantiated
    private ASCIIUtility() { }
  
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed integer in the given radix . The range extends 
     * from <code>start</code> till, but not including <code>end</code>. <p>
     *
     * Based on java.lang.Integer.parseInt()
     */
    public static int parseInt(byte[] b, int start, int end, int radix)
    throws NumberFormatException {
  if (b == null)
      throw new NumberFormatException("null");
  
  int result = 0;
  boolean negative = false;
  int i = start;
  int limit;
  int multmin;
  int digit;

  if (end > start) {
      if (b[i] == '-') {
    negative = true;
    limit = Integer.MIN_VALUE;
    i++;
      } else {
    limit = -Integer.MAX_VALUE;
      }
      multmin = limit / radix;
      if (i < end) {
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException(
      "illegal number: " + toString(b, start, end)
      );
    } else {
        result = -digit;
    }
      }
      while (i < end) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException("illegal number");
    }
    if (result < multmin) {
        throw new NumberFormatException("illegal number");
    }
    result *= radix;
    if (result < limit + digit) {
        throw new NumberFormatException("illegal number");
    }
    result -= digit;
      }
  } else {
      throw new NumberFormatException("illegal number");
  }
  if (negative) {
      if (i > start + 1) {
    return result;
      } else {  /* Only got "-" */
    throw new NumberFormatException("illegal number");
      }
  } else {
      return -result;
  }
    }

    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed integer . The range extends from 
     * <code>start</code> till, but not including <code>end</code>. <p>
     */
    public static int parseInt(byte[] b, int start, int end)
    throws NumberFormatException {
  return parseInt(b, start, end, 10);
    }

    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed long in the given radix . The range extends 
     * from <code>start</code> till, but not including <code>end</code>. <p>
     *
     * Based on java.lang.Long.parseLong()
     */
    public static long parseLong(byte[] b, int start, int end, int radix)
    throws NumberFormatException {
  if (b == null)
      throw new NumberFormatException("null");
  
  long result = 0;
  boolean negative = false;
  int i = start;
  long limit;
  long multmin;
  int digit;

  if (end > start) {
      if (b[i] == '-') {
    negative = true;
    limit = Long.MIN_VALUE;
    i++;
      } else {
    limit = -Long.MAX_VALUE;
      }
      multmin = limit / radix;
      if (i < end) {
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException(
      "illegal number: " + toString(b, start, end)
      );
    } else {
        result = -digit;
    }
      }
      while (i < end) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException("illegal number");
    }
    if (result < multmin) {
        throw new NumberFormatException("illegal number");
    }
    result *= radix;
    if (result < limit + digit) {
        throw new NumberFormatException("illegal number");
    }
    result -= digit;
      }
  } else {
      throw new NumberFormatException("illegal number");
  }
  if (negative) {
      if (i > start + 1) {
    return result;
      } else {  /* Only got "-" */
    throw new NumberFormatException("illegal number");
      }
  } else {
      return -result;
  }
    }

    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed long . The range extends from 
     * <code>start</code> till, but not including <code>end</code>. <p>
     */
    public static long parseLong(byte[] b, int start, int end)
    throws NumberFormatException {
  return parseLong(b, start, end, 10);
    }

    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a String. The range extends from <code>start</code>
     * till, but not including <code>end</code>. <p>
     */
    public static String toString(byte[] b, int start, int end) {
  int size = end - start;
  char[] theChars = new char[size];

  for (int i = 0, j = start; i < size; )
      theChars[i++] = (char)(b[j++]&0xff);
  
  return new String(theChars);
    }

    public static String toString(ByteArrayInputStream is) {
  int size = is.available();
  char[] theChars = new char[size];
  byte[] bytes    = new byte[size];

  is.read(bytes, 0, size);
  for (int i = 0; i < size;)
      theChars[i] = (char)(bytes[i++]&0xff);
  
  return new String(theChars);
    }


    public static byte[] getBytes(String s) {
  char [] chars= s.toCharArray();
  int size = chars.length;
  byte[] bytes = new byte[size];
      
  for (int i = 0; i < size;)
      bytes[i] = (byte) chars[i++];
  return bytes;
    }

    public static byte[] getBytes(InputStream is) throws IOException {

  int len;
  int size = 1024;
  byte [] buf;


  if (is instanceof ByteArrayInputStream) {
      size = is.available();
      buf = new byte[size];
      len = is.read(buf, 0, size);
  }
  else {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      buf = new byte[size];
      while ((len = is.read(buf, 0, size)) != -1)
    bos.write(buf, 0, len);
      buf = bos.toByteArray();
  }
  return buf;
    }
}

   
    
    
    
    
    
  








Related examples in the same category

1.Base64 encoding/decoding.
2.Decodes Base64 data into octects
3.Implementation of MIME's Base64 encoding and decoding conversions.
4.Encode/decode for RFC 2045 Base64 as defined by RFC 2045
5.Encode/decode for RFC 2045 Base64 as defined by RFC 2045, N. Freed and N. Borenstein.
6.Encodes and decodes to and from Base64 notation.
7.Encodes hex octects into Base64
8.Helper class to provide Base64 encoding routines.
9.Represents a collection of 64 boolean (on/off) flags.
10.byte to be tested if it is Base64 alphabet
11.to Base64
12.One of the fastest implementation of the Base64 encoding. Jakarta and others are slower
13.array of byte to encode
14.Codes number up to radix 62
15.A Base64 Encoder/Decoder
16.A fast and memory efficient class to encode and decode to and from BASE64 in full accordance with RFC 2045
17.BASE64 encoder implementation
18.Base-64 Encoder - translates from base-64 text into binary
19.Base64 Character encoder as specified in RFC1113
20.Base64 Utils
21.Base64 encoder/decoder
22.Base64 from by Funambol, Inc.
23.Convert to hex from byte arrays and back
24.Converting hexadecimal strings
25.Encode and decode data in Base64 format as described in RFC 1521
26.Encode and decode integers, times, and internationalized strings to and from popular binary formats
27.Encoding of raw bytes to base64-encoded characters, and decoding of base64 characters to raw bytes
28.Performs Base64 encoding and/or decoding
29.Provides Base64 encoding and decoding as defined by RFC 2045
30.Provides Base64 encoding and decoding with URL and filename safe alphabet as defined by RFC 3548, section 4.
31.Provides utility methods to Base64 encode data
32.QP Encoder Stream
33.A class to decode Base64 streams and strings.
34.A class to encode Base64 streams and strings.
35.Encodes binary data to plain text as Base64
36.A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance with RFC 2045.
37.Decodes InputStreams which contain binary data in base64 form
38.Base 64 Converter
39.Base64 from org.cspoker.common.util
40.Base64 converted from code at http://iharder.sourceforge.net/base64/
41.Encodes and decodes to and from Base64 notation.
42.Simple Base64 string decoding function
43.Class to represent unsigned 64-bit numbers.
44.A Base64 encoder/decoder.
45.The Base64 utility class implements Base-64 and Base-85 encoding and decoding algorithms.
46.Provides Base64 encoding and decoding
47.Code to read and write Base64-encoded text.
48.Base32 encoding/decoding class.