Java tutorial
/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you under the Apache License, Version 2.0 (the * * "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * * KIND, either express or implied. See the License for the * * specific language governing permissions and limitations * * under the License. * ****************************************************************/ import java.io.InputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.IOException; /** * A Reader for use with SMTP or other protocols in which lines * must end with CRLF. Extends Reader and overrides its * readLine() method. The Reader readLine() method cannot * serve for SMTP because it ends lines with either CR or LF alone. */ public class CRLFTerminatedReader extends Reader { public class TerminationException extends IOException { private int where; public TerminationException(int where) { super(); this.where = where; } public TerminationException(String s, int where) { super(s); this.where = where; } public int position() { return where; } } public class LineLengthExceededException extends IOException { public LineLengthExceededException(String s) { super(s); } } /** * Constructs this CRLFTerminatedReader. * @param in an InputStream * @param charsetName the String name of a supported charset. * "ASCII" is common here. * @throws UnsupportedEncodingException if the named charset * is not supported */ InputStream in; public CRLFTerminatedReader(InputStream in) { this.in = in; } public CRLFTerminatedReader(InputStream in, String enc) throws UnsupportedEncodingException { this(in); } private StringBuffer lineBuffer = new StringBuffer(); private final int EOF = -1, CR = 13, LF = 10; private int tainted = -1; /** * Read a line of text which is terminated by CRLF. The concluding * CRLF characters are not returned with the String, but if either CR * or LF appears in the text in any other sequence it is returned * in the String like any other character. Some characters at the * end of the stream may be lost if they are in a "line" not * terminated by CRLF. * * @return either a String containing the contents of a * line which must end with CRLF, or null if the end of the * stream has been reached, possibly discarding some characters * in a line not terminated with CRLF. * @throws IOException if an I/O error occurs. */ public String readLine() throws IOException { //start with the StringBuffer empty lineBuffer.delete(0, lineBuffer.length()); /* This boolean tells which state we are in, * depending upon whether or not we got a CR * in the preceding read(). */ boolean cr_just_received = false; // Until we add support for specifying a maximum line lenth as // a Service Extension, limit lines to 2K, which is twice what // RFC 2821 4.5.3.1 requires. while (lineBuffer.length() <= 2048) { int inChar = read(); if (!cr_just_received) { //the most common case, somewhere before the end of a line switch (inChar) { case CR: cr_just_received = true; break; case EOF: return null; // premature EOF -- discards data(?) case LF: //the normal ending of a line if (tainted == -1) tainted = lineBuffer.length(); // intentional fall-through default: lineBuffer.append((char) inChar); } } else { // CR has been received, we may be at end of line switch (inChar) { case LF: // LF without a preceding CR if (tainted != -1) { int pos = tainted; tainted = -1; throw new TerminationException("\"bare\" CR or LF in data stream", pos); } return lineBuffer.toString(); case EOF: return null; // premature EOF -- discards data(?) case CR: //we got two (or more) CRs in a row if (tainted == -1) tainted = lineBuffer.length(); lineBuffer.append((char) CR); break; default: //we got some other character following a CR if (tainted == -1) tainted = lineBuffer.length(); lineBuffer.append((char) CR); lineBuffer.append((char) inChar); cr_just_received = false; } } } //while throw new LineLengthExceededException("Exceeded maximum line length"); }//method readLine() public int read() throws IOException { return in.read(); } public boolean ready() throws IOException { return in.available() > 0; } public int read(char cbuf[], int off, int len) throws IOException { byte[] temp = new byte[len]; int result = in.read(temp, 0, len); for (int i = 0; i < result; i++) cbuf[i] = (char) temp[i]; return result; } public void close() throws IOException { in.close(); } }