Package org.subethamail.smtp.io

Source Code of org.subethamail.smtp.io.DotTerminatedInputStream

package org.subethamail.smtp.io;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

/**
* An InputStream class that terminates the stream when it encounters a US-ASCII
* encoded dot CR LF byte sequence immediately following a CR LF line end.
*/
public class DotTerminatedInputStream extends InputStream
{
  /**
   * The wrapped input stream.
   */
  private InputStream in;

  /**
   * The last bytes returned by the {@link #read()} function. The first byte
   * in the array contains the byte returned by the penultimate read() call.
   * The second byte in the array contains the byte returned by the last
   * read() call. EOF (-1) is not shifted into the array. It's initial value
   * is CR LF, so the first character of the stream is considered to be the
   * first character of a line. This makes it possible to receive empty data.
   */
  private final byte[] lastBytes = new byte[]{
      '\r', '\n'
  };

  /**
   * The buffer which contains the bytes read from the underlying stream in
   * advance. These bytes are not yet returned by the {@link #read()}
   * function. Null means uninitialized.
   */
  private int[] nextBytes = null;

  /**
   * Indicates that the last byte - not including the terminating sequence -
   * of the wrapped stream was already returned by {@link #read()}
   */
  private boolean endReached = false;

  /**
   * A constructor for this object that takes a stream to be wrapped and a
   * terminating character sequence.
   *
   * @param in
   *            the <code>InputStream</code> to be wrapped
   * @throws IllegalArgumentException
   *             if the terminator array is null or empty
   */
  public DotTerminatedInputStream(InputStream in)
  {
    this.in = in;
  }

  @Override
  public int read() throws IOException
  {
    if (nextBytes == null)
      initNextBytes();
    if (endReached)
      return -1;
    if (lastBytesAreCrLf() && nextBytesAreDotCrLf())
    {
      endReached = true;
      return -1;
    }
    int result = nextBytes[0];
    if (result == -1)
    {
      // End of stream reached without seeing the terminator
      throw new EOFException("Pre-mature end of <CRLF>.<CRLF> terminated data");
    }
    readWrappedStream();
    return result;
  }

  private void initNextBytes() throws IOException
  {
    nextBytes = new int[3];
    nextBytes[0] = in.read();
    nextBytes[1] = in.read();
    nextBytes[2] = in.read();
  }

  private boolean lastBytesAreCrLf()
  {
    return lastBytes[0] == '\r' && lastBytes[1] == '\n';
  }

  private boolean nextBytesAreDotCrLf()
  {
    return nextBytes[0] == '.' && nextBytes[1] == '\r' && nextBytes[2] == '\n';
  }

  /**
   * Shifts bytes in the buffers, reads a byte from the wrapped stream, and
   * places it at the end of the nextBytes buffer.
   */
  private void readWrappedStream() throws IOException
  {
    lastBytes[0] = lastBytes[1];
    // casting is safe, this function is not called if an - unexpected - EOF
    // was read
    lastBytes[1] = (byte) nextBytes[0];
    nextBytes[0] = nextBytes[1];
    nextBytes[1] = nextBytes[2];
    nextBytes[2] = in.read();
  }
}
TOP

Related Classes of org.subethamail.smtp.io.DotTerminatedInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.